#pragma once

#include <unordered_map>
#include <sstream>
#include "Util.hpp"

namespace cloud
{
    class DataManager
    {
    public:
        DataManager(const std::string &backup_file) : backup_file_(backup_file)
        {
            InitLoad();
        }

        // 持久化。规定持久化存储格式：path Etag\npath Etag\npath Etag\npath Etag\n ...
        bool Storage()
        {
            // 1. 获取所有的备份信息
            std::stringstream ss;
            for (auto it = table_.begin(); it != table_.end(); ++it)
            {
                // 2. 将所有备份信息按规定格式组织起来
                ss << it->first << " " << it->second << "\n";
            }
            // 3. 将组织起来的数据写入文件，进行持久化
            FileUtil fu(backup_file_);
            fu.SetContent(ss.str());
            return true;
        }

        // 客户端启动初始化加载
        bool InitLoad()
        {
            // 1. 将文件中的所有数据读取出来
            FileUtil fu(backup_file_);
            std::string body;
            fu.GetContent(&body);
            // 2. 按规定格式进行数据解析，添加到 table_ 中
            std::vector<std::string> arry;
            int n = AnalysisStr(body, "\n", &arry);
            for (auto &it : arry)
            {
                std::vector<std::string> tmp;
                int m = AnalysisStr(it, " ", &tmp);
                if (tmp.size() != 2)
                    continue;

                table_[tmp[0]] = tmp[1];
                (void)m;
            }
            (void)n;
            return true;
        }

        // 添加新的信息
        bool Insert(const std::string &file_path, const std::string &Etag)
        {
            table_[file_path] = Etag;
            Storage();
            return true;
        }

        // 更新信息
        bool Update(const std::string &file_path, const std::string &Etag)
        {
            table_[file_path] = Etag;
            Storage();
            return true;
        }

        // 获取信息
        bool GetEtagByPath(const std::string &file_path, std::string *Etag)
        {
            auto it = table_.find(file_path);
            if (it == table_.end())
            {
                std::cout << "GetEtagByPath: not have" << " " << file_path << "'s Etag" << std::endl;
                return false;
            }
            *Etag = it->second;
            return true;
        }

    private:
        // 返回值为 arry 数组的元素个数
        int AnalysisStr(const std::string &str, const std::string &sep, std::vector<std::string> *arry)
        {
            int count = 0;
            int pos = 0, index = 0;
            while (1)
            {
                pos = str.find(sep, index);
                if (pos == std::string::npos)
                {
                    break;
                }

                // "abc  cdb "
                if (pos == index)
                {
                    index = pos + sep.size();
                    continue;
                }

                std::string tmp = str.substr(index, pos - index);
                arry->push_back(tmp);
                count++;
                index = pos + sep.size();
            }

            // "abc bcd"
            if (index < str.size())
            {
                arry->push_back(str.substr(index));
                count++;
            }
            return count;
        }

    private:
        // 备份文件信息的持久化存储路径文件
        std::string backup_file_;
        // 备份文件信息在内存中的存储，方便快速查询 <file_path, Etag>
        std::unordered_map<std::string, std::string> table_;
    };
}